package com.wjk.cms.service.impl;

import com.wjk.cms.exception.ApplicationException;

import com.wjk.cms.service.VerificationCodeService;
import com.wjk.cms.util.lock.LockUtil;
import com.wjk.cms.util.sms.SmsUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
public class VerificationCodeServiceImpl implements VerificationCodeService {

    private static final long VERIFICATION_CODE_EXPIRES_IN_SECONDS = 300;


    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private LockUtil lockUtil;

    @Override
    public boolean send(String phone, String channel) {
        performLimitControl(phone);
        String code = generateCode();
        saveCode(phone, code);
        return SmsUtil.sendVerificationCode(phone, code, channel) == 0;
    }

    private void performLimitControl(String phone) {
        String key = "scm:verification-code:limit-control:" + phone;
        if (!lockUtil.lock(key, 62)) { // 此处故意多设置了2秒
            throw new ApplicationException("操作过于频繁，请60秒后重试");
        }
    }

    @Override
    public void verify(String phone, String code) {


        String codeInRedis = getCode(phone);
        if (codeInRedis == null || !codeInRedis.equals(code)) {
            throw new ApplicationException("验证码错误");
        }
        removeCode(phone);
    }

    private String getRedisKey(String phone) {
        return "phonecode:" + phone;
    }

    private String generateCode() {
        return String.valueOf(ThreadLocalRandom.current().nextInt(9000) + 1000);
    }

    private void saveCode(String phone, String code) {
        redisTemplate.opsForValue().set(getRedisKey(phone), code, VERIFICATION_CODE_EXPIRES_IN_SECONDS, TimeUnit.SECONDS);
    }

    private String getCode(String phone) {
        return redisTemplate.opsForValue().get(getRedisKey(phone));
    }

    private void removeCode(String phone) {
        redisTemplate.delete(getRedisKey(phone));
    }



}
